using System;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.JSInterop;

namespace MyBlogServer.Services
{
    public interface IJwtAuthService
    {
        Task<string> GenerateTokenAsync(string username);
        Task StoreTokenAsync(string token);
        Task<bool> IsTokenValidAsync();
        Task<string> GetStoredTokenAsync();
        Task ClearTokenAsync();
        Task<string> GetUsernameFromTokenAsync(string token);
    }

    public class JwtAuthService : IJwtAuthService
    {
        private readonly string _secretKey;
        private readonly string _issuer;
        private readonly string _audience;
        private readonly IJSRuntime _jsRuntime;

        public JwtAuthService(IConfiguration configuration, IJSRuntime jsRuntime)
        {
            _secretKey = configuration["Jwt:SecretKey"] ?? throw new ArgumentNullException(nameof(configuration));
            _issuer = configuration["Jwt:Issuer"] ?? throw new ArgumentNullException(nameof(configuration));
            _audience = configuration["Jwt:Audience"] ?? throw new ArgumentNullException(nameof(configuration));
            _jsRuntime = jsRuntime;
        }

        public async Task<string> GenerateTokenAsync(string username)
        {
            var tokenHandler = new JsonWebTokenHandler();
            var key = Encoding.ASCII.GetBytes(_secretKey);

            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new[]
                {
                    new Claim(ClaimTypes.Name, username),
                    new Claim(ClaimTypes.NameIdentifier, username)
                }),
                Expires = DateTime.UtcNow.AddHours(1),
                Issuer = _issuer,
                Audience = _audience,
                SigningCredentials = new SigningCredentials(
                    new SymmetricSecurityKey(key),
                    SecurityAlgorithms.HmacSha256Signature)
            };

            return tokenHandler.CreateToken(tokenDescriptor);
        }

        public async Task StoreTokenAsync(string token)
        {
            try
            {
                // 存储 Token 到浏览器的 localStorage
                await _jsRuntime.InvokeVoidAsync("localStorage.setItem", "authToken", token);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"存储Token时发生错误: {ex.Message}");
            }
        }

        public async Task<bool> IsTokenValidAsync()
        {
            try
            {
                // 从存储中获取Token
                var token = await GetStoredTokenAsync();
                if (string.IsNullOrEmpty(token))
                {
                    return false;
                }

                // 验证Token
                return IsTokenValid(token);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"验证Token时发生错误: {ex.Message}");
                return false;
            }
        }
        
        public async Task<string> GetStoredTokenAsync()
        {
            try
            {
                return await _jsRuntime.InvokeAsync<string>("localStorage.getItem", "authToken");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"获取存储的Token时发生错误: {ex.Message}");
                return string.Empty;
            }
        }
        
        public async Task ClearTokenAsync()
        {
            try
            {
                await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", "authToken");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"清除Token时发生错误: {ex.Message}");
            }
        }
        
        public async Task<string> GetUsernameFromTokenAsync(string token)
        {
            try
            {
                if (string.IsNullOrEmpty(token))
                {
                    return string.Empty;
                }

                var tokenHandler = new JsonWebTokenHandler();
                var key = Encoding.ASCII.GetBytes(_secretKey);
                
                var validationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = true,
                    ValidIssuer = _issuer,
                    ValidateAudience = true,
                    ValidAudience = _audience,
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.Zero
                };

                var validationResult = await tokenHandler.ValidateTokenAsync(token, validationParameters);
                if (!validationResult.IsValid)
                {
                    return string.Empty;
                }

                var jsonWebToken = (JsonWebToken)validationResult.SecurityToken;
                return jsonWebToken.Subject ?? string.Empty;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"从Token获取用户名时发生错误: {ex.Message}");
                return string.Empty;
            }
        }
        
        private bool IsTokenValid(string token)
        {
            try
            {
                var tokenHandler = new JsonWebTokenHandler();
                var key = Encoding.ASCII.GetBytes(_secretKey);
                
                var validationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = true,
                    ValidIssuer = _issuer,
                    ValidateAudience = true,
                    ValidAudience = _audience,
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.Zero
                };

                var validationResult = tokenHandler.ValidateToken(token, validationParameters);
                return validationResult.IsValid;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}